using Castle.DynamicProxy;
using Microsoft.AspNetCore.Mvc.TagHelpers.Cache;
using Microsoft.IdentityModel.Logging;
using Newtonsoft.Json;
using Serilog;
using Serilog.Core;
using System.Diagnostics;
using System.Reflection;
using System.Threading.Tasks;

namespace xjjxmm.infrastructure.xjjxmmLog.LogKit
{
    public class LoggerInterceptor : IInterceptor
    {
        private readonly LoggerAsyncInterceptor _interceptor;

        public LoggerInterceptor(LoggerAsyncInterceptor interceptor)
        {
            _interceptor = interceptor;
        }

        public void Intercept(IInvocation invocation)
        {
            _interceptor.ToInterceptor().Intercept(invocation);
        }

    }

    public class LoggerAsyncInterceptor : IAsyncInterceptor
    {
        private void LogStart(IInvocation invocation)
        {
            //记录日志
            var logAttribute = invocation.Method.GetCustomAttribute<XjjXmmLogAttribute>();
            if(logAttribute == null)
            {
                return;
            }

            var logger = Log.ForContext(invocation.TargetType);
            //获取执行信息
            var methodName = invocation.Method.Name;
            
            if (logAttribute.Ignore || logAttribute.IgnoreInput)
            {
                logger.Information("开始执行: {MethodName}，", methodName);
            }
            else
            {
                var input = invocation.Arguments;
                logger.Information("开始执行: {MethodName}，入参： {@Input}", methodName, input);
            }
        }

        private void LogEnd(IInvocation invocation, object? result, double ms)
        {
            //记录日志
            var logAttribute = invocation.Method.GetCustomAttribute<XjjXmmLogAttribute>();
            if (logAttribute == null)
            {
                return;
            }

            var logger = Log.ForContext(invocation.TargetType);
            //获取执行信息
            var methodName = invocation.Method.Name;

            //记录日志

            if (logAttribute.Ignore || logAttribute.IgnoreOutput)
            {
                logger.Information("结束执行: {MethodName}， 用时: {Ms}", methodName, ms);

            }
            else
            {
                //记录日志
                logger.Information("结束执行: {MethodName}，返回结果：{@Task}, 用时: {Ms}", methodName, result, ms);
            }
        }

        public void InterceptSynchronous(IInvocation invocation)
        {
            var watch = Stopwatch.StartNew();
           
            LogStart(invocation);

            invocation.Proceed();

            var task = invocation.ReturnValue;

            watch.Stop();
            var ms = watch.Elapsed.TotalSeconds;

            LogEnd(invocation, task, ms);
            //invocation.ReturnValue = task;
        }

        public void InterceptAsynchronous(IInvocation invocation)
        {
            invocation.ReturnValue = InternalInterceptAsynchronous(invocation);
        }

        private async Task InternalInterceptAsynchronous(IInvocation invocation)
        {
            var watch = Stopwatch.StartNew();

            LogStart(invocation);

            //执行方法
            invocation.Proceed();
            var task = (Task)invocation.ReturnValue;
            await task;

            watch.Stop();
            var ms = watch.Elapsed.TotalSeconds;

            LogEnd(invocation, task, ms);
        }

        public void InterceptAsynchronous<TResult>(IInvocation invocation)
        {
            //调用业务方法
            invocation.ReturnValue = InternalInterceptAsynchronous<TResult>(invocation);
        }

        private async Task<TResult> InternalInterceptAsynchronous<TResult>(IInvocation invocation)
        {
            var watch = Stopwatch.StartNew();
            LogStart(invocation);

            invocation.Proceed();


            var task = (Task<TResult>)invocation.ReturnValue;
            TResult result = await task;

            watch.Stop();
            var ms = watch.Elapsed.TotalSeconds;

            LogEnd(invocation, result, ms);

            return result;
        }
    }
}
